﻿using System;
using System.IO;
using System.Runtime.Serialization;
using System.Runtime.Serialization.Formatters.Binary;
using System.Text;
using System.Xml;
using System.Xml.Serialization;

namespace AnnouncementManager
{
    public abstract class XmlSerializationHelper
    {
        #region Constructor

        #endregion

        /// <summary>
        /// Serialize an object using the BinaryFormatter.
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A Base64 string.</returns>
        public static string BinarySerialize(object item)
        {
            if (item != null)
            {
                using (var memoryStream = new MemoryStream())
                {
                    var binaryFormatter = new BinaryFormatter();
                    binaryFormatter.Serialize(memoryStream, item);
                    return Convert.ToBase64String(memoryStream.ToArray());
                }
            }
            return null;
        }

        /// <summary>
        /// Deserialize an Base64 string into an object using the BinaryFormatter.
        /// </summary>
        /// <param name="item">The string that must be deserialized.</param>
        /// <returns>The object deserialized.</returns>
        public static object BinaryDeserialize(string item)
        {
            if (!string.IsNullOrEmpty(item))
            {
                byte[] buffer = Encoding.UTF8.GetBytes(item);
                if (buffer.Length > 0)
                {
                    using (var memoryStream = new MemoryStream(Convert.FromBase64String(item)))
                    {
                        var binaryFormatter = new BinaryFormatter();
                        return binaryFormatter.Deserialize(memoryStream);
                    }
                }
            }
            return null;
        }

        /// <summary>
        /// Serialize an object using the XmlSerializer.
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A XML string.</returns>
        public static string XmlSerialize(object item)
        {
            string serialXml = String.Empty;
            try
            {
                // Serialize the object
                var xmlSerializer = new XmlSerializer(item.GetType());
                using (var stringWriter = new StringWriter())
                {
                    xmlSerializer.Serialize(stringWriter, item);
                    serialXml = stringWriter.ToString();
                    stringWriter.Flush();
                }
            }
            catch
            {
            }
            return serialXml;
        }

        /// <summary>
        /// Deserialize an XML string into an object using the XmlSerializer.
        /// </summary>
        /// <param name="item">The string that must be deserialized.</param>
        /// <returns>The object deserialized.</returns>
        public static T XmlDeserialize<T>(string item)
        {
            using (var stringReader = new StringReader(item))
            {
                var serializer = new XmlSerializer(typeof(T));
                return (T)serializer.Deserialize(stringReader);
            }

            return default(T);
        }

        /// <summary>
        /// Serializes object with no namespace and no xml declaration tag. Returns pure xml of the object
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A pure XML string</returns>
        public static string XmlSerializeToPureXml(Object item)
        {
            string serialXml;
            // set XML writer settings
            var xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.OmitXmlDeclaration = true;
            xmlWriterSettings.Indent = true;
            xmlWriterSettings.CloseOutput = true;
            xmlWriterSettings.Encoding = Encoding.UTF8;

            using (var stringWriter = new StringWriter())
            {
                // create xml using the settings
                using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlWriterSettings))
                {
                    var xmlSerializer = new XmlSerializer(item.GetType());
                    //Empty namespace
                    var xmlSerializerNamespaces = new XmlSerializerNamespaces();
                    xmlSerializerNamespaces.Add(String.Empty, String.Empty);

                    xmlSerializer.Serialize(xmlWriter, item, xmlSerializerNamespaces);
                    // get the xml and clean up
                    serialXml = stringWriter.ToString();
                    xmlWriter.Flush();
                }
                stringWriter.Flush();
            }
            
            return serialXml;
        }

        /// <summary>
        /// Serialize with no xml declaration
        /// </summary>
        /// <param name="item">The type of the serialized object.</param>
        /// <returns>A XML with string with no xml declaration</returns>
        public static string XmlSerializeWithNoXmlDeclaration(Object item)
        {
            string serialXml;
            // set XML writer settings
            var xmlWriterSettings = new XmlWriterSettings();
            xmlWriterSettings.OmitXmlDeclaration = true;
            xmlWriterSettings.Indent = true;
            xmlWriterSettings.CloseOutput = true;
            xmlWriterSettings.Encoding = Encoding.UTF8;

            using (var stringWriter = new StringWriter())
            {
                // create xml using the settings
                using (XmlWriter xmlWriter = XmlWriter.Create(stringWriter, xmlWriterSettings))
                {
                    var xmlSerializer = new XmlSerializer(item.GetType());
                    xmlSerializer.Serialize(xmlWriter, item);
                    // get the xml and clean up
                    serialXml = stringWriter.ToString();
                    xmlWriter.Flush();
                }
                stringWriter.Flush();
            }
            //
            return serialXml;
        }

        /// <summary>
        /// Serialize an object using the DataContractSerializer.
        /// </summary>
        /// <param name="item">The object that must be serialized</param>
        /// <returns>A XML string.</returns>
        public static string DataContractSerialize(object item)
        {
            if (item != null)
            {
                using (var memoryStream = new MemoryStream())
                {
                    var serializer = new DataContractSerializer(item.GetType());
                    serializer.WriteObject(memoryStream, item);
                    return Encoding.UTF8.GetString(memoryStream.ToArray());
                }
            }
            return null;
        }

        /// <summary>
        /// Deserialize an XML string into an object using the DataContractSerializer.
        /// </summary>
        /// <param name="item">The string that must be deserialized.</param>
        /// <returns>The object deserialized.</returns>
        public static T DataContractDeserialize<T>(string item)
        {
            XmlDictionaryReader xmlDictionaryReader = null;
            try
            {
                xmlDictionaryReader = XmlDictionaryReader.CreateTextReader(Encoding.UTF8.GetBytes(item), XmlDictionaryReaderQuotas.Max);
                var serializer = new DataContractSerializer(typeof(T));
                return (T)serializer.ReadObject(xmlDictionaryReader, false);
            }
            finally
            {
                if (xmlDictionaryReader != null)
                {
                    xmlDictionaryReader.Close();
                }
            }

            return default(T);
        }
    }
}